library(ggplot2)
library(sf)
Linking to GEOS 3.10.2, GDAL 3.4.1, PROJ 8.2.1; sf_use_s2() is TRUE
library(dplyr)

Attaching package: ‘dplyr’

The following objects are masked from ‘package:stats’:

    filter, lag

The following objects are masked from ‘package:base’:

    intersect, setdiff, setequal, union
library(spatialreg)
Loading required package: spData
To access larger datasets in this package, install the spDataLarge package with: `install.packages('spDataLarge',
repos='https://nowosad.github.io/drat/', type='source')`
Loading required package: Matrix
library(spdep)

Attaching package: ‘spdep’

The following objects are masked from ‘package:spatialreg’:

    get.ClusterOption, get.coresOption, get.mcOption, get.VerboseOption, get.ZeroPolicyOption, set.ClusterOption, set.coresOption,
    set.mcOption, set.VerboseOption, set.ZeroPolicyOption
rm(list=ls())
mypath <- "./DataBackups/"
profession_names <- c(
  "sales professions",
  "mechatronics, energy, and electrical professions",
  "professions in business management and organization",
  "medical health professions",
  "machine and vehicle technology professions",
  "all professions"
)

kreise <- sf::st_read("./DataPreparation/Shapes/Kreise/vg1000_12-31.utm32s.shape.ebenen/vg1000_ebenen_1231/VG1000_KRS.shp") # though not imported directly, all other auxiliary files must be present in the path
Reading layer `VG1000_KRS' from data source 
  `/home/dennis/Desktop/Spatial Regression Analysis_cleaned/DataPreparation/Shapes/Kreise/vg1000_12-31.utm32s.shape.ebenen/vg1000_ebenen_1231/VG1000_KRS.shp' 
  using driver `ESRI Shapefile'
Simple feature collection with 424 features and 25 fields
Geometry type: MULTIPOLYGON
Dimension:     XY
Bounding box:  xmin: 280353.1 ymin: 5235878 xmax: 921261.6 ymax: 6101482
Projected CRS: ETRS89 / UTM zone 32N
kreise <- st_transform(kreise, "WGS84")
kreise_merged <- kreise %>%
  group_by(SN_L) %>%
  summarize(geometry = st_union(geometry))
library(stringr)
library(ggrepel)


model_list <- list()

graphics_list <- list()
spatial_clustering_list <- list()
load(file = "./DataBackups/weights_data.RData")

for (p in profession_names)
{
#p <- profession_names[1]  
  
load(paste0(mypath,p,"M.Rdata"))
load(file = "./DataBackups/weights_data.RData")

print(p)

target = "M"
formula_base <- as.formula(paste0(target,"  ~ U + V "))
formula <- as.formula(paste0(target,"   ~ U + V + unemp25 + cons + highSE +  medSE  "))
formula_pub_num <- as.formula(paste0(target,"   ~ U + V + unemp25 + cons + highSE + medSE  + Agglomeration"))
target = "M"



profession_new$Agglomeration <- profession_new$AgglomerationPublicPop49


# Begin Weight Matrix computation
columns_of_interest <- c('M','U', 'V', 'unemp25', 'cons', 'lowSE', 'medSE', 'Agglomeration')
# Replace Inf and -Inf with NA in the specified columns
profession_new[columns_of_interest] <- lapply(profession_new[columns_of_interest], function(x) replace(x, is.infinite(x), NA))
# Remove rows with any NA values in the specified columns
profession_new <- profession_new[complete.cases(profession_new[columns_of_interest]), ]

best_Weights_public_pop <- best_Weights_public_pop_mat[colnames(best_Weights_public_pop_mat) %in% profession_new$region,colnames(best_Weights_public_pop_mat) %in% profession_new$region]

################
library(dplyr)

distances_relevant_pop <- merge(distances_relevant,final, by.x="city...1",by.y="city")
distances_relevant_pop <- merge(distances_relevant_pop,final,by.x="city...4",by.y="city")

profession_new <- profession_new[!is.na(profession_new$OpenPositions),]

## As all Professions have different Regions, we need to Reduce the matrix to relevant regions. As the initial matrix, already does not contain all regions, it is easier to re-calculate evrything.
distances_relevant_test_public <-  distances_relevant_pop %>% group_by(ABDistrict...6) %>% mutate(district_pop = sum(unique(maxPopulation.y))) %>% ungroup %>% filter(ABDistrict...3 != ABDistrict...6)  %>%  filter(public <= 51.28167) %>% group_by(city...1, ABDistrict...3, ABDistrict...6) %>%  summarise(district_pop = max(district_pop), count= sum(unique(maxPopulation.y)), Weight=count/district_pop, .groups="keep") %>% group_by(ABDistrict...3, ABDistrict...6) %>% summarise(Weight=mean(Weight), .groups="keep")


Weights_public_pop  <- matrix(0, nrow=nrow(profession_new), ncol=nrow(profession_new))
  row.names(Weights_public_pop)<- profession_new$region
  colnames(Weights_public_pop) <- profession_new$region

  for(i in 1:nrow(distances_relevant_test_public))
  {
    Weights_public_pop[row.names(Weights_public_pop)==distances_relevant_test_public$ABDistrict...3[i], colnames(Weights_public_pop)==distances_relevant_test_public$ABDistrict...6[i]]<- distances_relevant_test_public$Weight[i]
  }
  
  Weights_public_pop <- Weights_public_pop/max(Weights_public_pop)

  model <- lmSLX(formula_pub_num , profession_new, mat2listw(Weights_public_pop, style="M"), na.action=na.omit, zero.policy=TRUE, Durbin=~  U + V  -1)

  model_list$x <- model
  names(model_list)<-c(names(model_list)[1:(length(names(model_list)))-1], p)
  
  #
  estimate_vector<- model$coefficients[-c(2,3,9:10)]
  estimate_values <- as.matrix(cbind("(Intercept)"=1,st_drop_geometry(profession_new[,names(estimate_vector[-c(1)])])))
  
  
  profession_new$Efficiency <- exp(estimate_values %*% estimate_vector) 

map_efficiency <- ggplot() + 
  geom_sf(data=districts, fill = "#e4e4e4") +
  geom_sf(data=st_as_sf(profession_new), aes(fill = Efficiency))+
  geom_sf(data=kreise_merged,fill=NA,
          color = "#ec7063",   
          lwd = 1.2) +
  theme(legend.text.align = 1)  +
  labs(fill = str_wrap(paste0("Efficiency for ", p), width = 50)) + 
  guides(
    fill = guide_colorbar(direction = "horizontal", title.hjust=0.5, title.position="top", barwidth = 20,  # Adjust this value to change the width of the colorbar
      barheight = 1  ), 
# Adjust rows for the fill legend
  ) +
  theme(
    legend.position = "bottom",
    legend.text = element_text(size = 18),
    legend.title = element_text(size = 18, face="bold"),
    legend.box = "horizontal",
    legend.box.just = "center",
    legend.spacing.x = unit(0.5, "cm") 
  )


map_efficiency <- map_efficiency +  scale_fill_gradientn(colors = custom_colors(100), na.value="#e4e4e4")
print(map_efficiency)


  graphics_list$x <- map_efficiency
  names(graphics_list)<-names(model_list)

}
[1] "sales professions"
Warning: style is M (missing); style should be set to a valid valueWarning: missing spatial weights styleWarning: The `legend.text.align` argument of `theme()` is deprecated as of ggplot2 3.5.0.
Please use theme(legend.text = element_text(hjust)) instead.
[1] "mechatronics, energy, and electrical professions"
[1] "professions in business management and organization"
[1] "medical health professions"
[1] "machine and vehicle technology professions"
[1] "all professions"


library(gridExtra)

Attaching package: ‘gridExtra’

The following object is masked from ‘package:dplyr’:

    combine
combined_plot <- do.call(grid.arrange, c(graphics_list, ncol = 2, nrow = 3))

print(combined_plot)
TableGrob (3 x 2) "arrange": 6 grobs
#combined_plot <- do.call(grid.arrange, c(spatial_clustering_list, ncol = 2, nrow = 3))
#print(combined_plot)
library(jtools)
library(huxtable)

Attaching package: ‘huxtable’

The following object is masked from ‘package:dplyr’:

    add_rownames

The following object is masked from ‘package:ggplot2’:

    theme_grey
# Combine model summaries into a single huxtable
ht <- export_summs(model_list$`all professions`,
                   model_list$`machine and vehicle technology professions`,
                   model_list$`mechatronics, energy, and electrical professions`,
                   model_list$`medical health professions`,
                   model_list$`professions in business management and organization`,
                   model_list$`sales professions`,
                   model.names = c("All Professions",
                                   "Machine & Vehicle Technology",
                                   "Mechatronics, Energy, Electrical",
                                   "Medical Health",
                                   "Business Management",
                                   "Sales"), 
  number_format = "%.3f", 
  statistics = c("logLik","AIC","BIC","N. obs." = "nobs"),
  stars = c(`***` = 0.001, `**` = 0.01, `*` = 0.05, `^` = 0.1))
Warning: The `tidy()` method for objects of class `SlX` is not maintained by the broom team, and is only supported through the `lm` tidier method. Please be cautious in interpreting and reporting broom output.
# Apply any additional formatting to the huxtable if needed
ht <- ht %>%
  
  set_header_rows(1, TRUE) %>%
  set_header_cols(1, TRUE)

# Display the huxtable
print_screen(ht)
            ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
                              All Professions    Machine & Vehicle       Mechatronics,      Medical Health   Business Management      Sales      
                                                    Technology        Energy, Electrical                                                         
                            ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
              (Intercept)          -0.509 *              -0.324                -0.482 *         -0.916 **             -0.551 *       -0.944 **   
                                   (0.207)               (0.218)               (0.196)          (0.338)               (0.225)        (0.313)     
              U                     0.681 ***             0.508 ***             0.694 ***        0.566 ***             0.500 ***      0.691 ***  
                                   (0.039)               (0.041)               (0.038)          (0.052)               (0.046)        (0.034)     
              V                     0.316 ***             0.503 ***             0.320 ***        0.446 ***             0.519 ***      0.319 ***  
                                   (0.039)               (0.042)               (0.038)          (0.050)               (0.045)        (0.033)     
              unemp25              -0.014                -0.006                -0.021 *          0.017                -0.008          0.005      
                                   (0.008)               (0.009)               (0.008)          (0.016)               (0.010)        (0.013)     
              cons                  0.051 *               0.002                 0.065 *          0.127 **              0.028          0.034      
                                   (0.025)               (0.027)               (0.025)          (0.042)               (0.029)        (0.036)     
              highSE               -0.002                 0.005                 0.017           -0.002                 0.007          0.034      
                                   (0.024)               (0.027)               (0.024)          (0.039)               (0.028)        (0.039)     
              medSE                 0.044                 0.042                 0.007            0.033                 0.050          0.092 ^    
                                   (0.030)               (0.033)               (0.029)          (0.048)               (0.034)        (0.047)     
              Agglomeration         0.019 ***            -0.003                 0.007            0.028 **              0.006          0.021 **   
                                   (0.005)               (0.005)               (0.005)          (0.009)               (0.007)        (0.008)     
              lag.U                -0.070 *              -0.084 **             -0.036            0.095                -0.015          0.005      
                                   (0.031)               (0.032)               (0.033)          (0.059)               (0.041)        (0.029)     
              lag.V                 0.069 *               0.086 **              0.035           -0.095                 0.015         -0.006      
                                   (0.032)               (0.033)               (0.034)          (0.059)               (0.042)        (0.029)     
                            ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
              logLik              299.984               276.552               276.644          193.812               247.251        232.410      
              AIC                -577.969              -531.104              -531.288         -365.623              -472.503       -442.819      
              BIC                -545.149              -498.825              -499.412         -335.053              -441.303       -410.228      
              N. obs.             146                   139                   134              119                   126            143          
            ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
              *** p < 0.001; ** p < 0.01; * p < 0.05; ^ p < 0.1.                                                                                 

Column names: names, All Professions, Machine & Vehicle Technology, Mechatronics, Energy, Electrical, Medical Health, Business Management, Sales
# Export to HTML
quick_html(ht, file = "./Outputs/Regressions/Profession_differences.html")
kf.service.services: KApplicationTrader: mimeType "x-scheme-handler/file" not found
kf.service.services: KApplicationTrader: mimeType "x-scheme-handler/file" not found

library(ggplot2)
library(dplyr)
library(tidyr)

Attaching package: ‘tidyr’

The following objects are masked from ‘package:Matrix’:

    expand, pack, unpack
library(stringr)
library(ggplot2)



# Extract coefficients and create a data frame
# Extract coefficients and create a data frame
# Extract coefficients, standard errors and create a data frame
coef_df <- do.call(rbind, lapply(names(model_list), function(profession) {
  model <- model_list[[profession]]
  tidy_model <- broom::tidy(model)
  tidy_model$Profession <- profession
  tidy_model
}))
Opening in existing browser session.
# Function to add line breaks to labels
add_line_breaks <- function(label, width = 30) {
  str_wrap(label, width = width)
}



 #Extract coefficients, standard errors and create a data frame
coef_df <- do.call(rbind, lapply(names(model_list), function(profession) {
  model <- model_list[[profession]]
  tidy_model <- broom::tidy(model)
  tidy_model$Profession <- profession
  tidy_model
}))

# Create an offset variable for the y-axis
coef_df <- coef_df %>%
  group_by(term) %>%
  mutate(offset = as.numeric(factor(Profession)) * 0.1) %>%  # Adjust the offset multiplier as needed
  ungroup()

# Add the English profession column



coef_df$term[coef_df$term=="(Intercept)"] <- "Efficiency"
coef_df$term[coef_df$term=="AgglomerationDistPop"] <- "Agglomeration"

coef_df$term[coef_df$term=="lag.U"] <- "U.lag"
coef_df$term[coef_df$term=="lag.V"] <- "V.lag"


coef_df1 <- coef_df[coef_df$term %in% c("U","V","U.lag","V.lag","Efficiency", "lambda"),]

coef_df2 <- coef_df[!(coef_df$term %in% c("U","V","U.lag","V.lag","Efficiency","lambda")),]

library(viridis)
Loading required package: viridisLite
library(scales)

Attaching package: ‘scales’

The following object is masked from ‘package:viridis’:

    viridis_pal

The following object is masked from ‘package:huxtable’:

    number_format
dark_viridis_colors <- viridis_pal(option = "G")(10)[3:8]

# Plot the coefficients with error bars and vertical offset

coef_df1$term <- factor(coef_df1$term, levels = c("lambda", "U.lag","V.lag", "U", "V",  "Efficiency" ))

plot_eff1 <- ggplot(coef_df1, aes(x = term, y = estimate, color = Profession))+
  geom_point(position = position_dodge(width = 0.8), size = 3) +
  geom_errorbar(aes(ymin = estimate - 1.96 * std.error, ymax = estimate +  1.96 *std.error),
                width = 0.2, size = 1, position = position_dodge(width = 0.8))+
  geom_vline(xintercept = 0, linetype = "solid", color = "black", size = 6) +
  coord_flip() +
  theme_minimal() +
  labs(
       x = "Coefficient Term",
       y = "Estimate",
       color = "Profession") +
theme(axis.text.x = element_text(size = 16),
        axis.text.y = element_text(size = 16),
        legend.position = "bottom",   legend.text = element_text(size = 14),
        plot.margin = margin(t = 10, r = 40, b = 10, l = 10),
  legend.title = element_text(size = 16),
  legend.title.position = "top",
  legend.box = "horizontal",
    # Adjust margins (top, right, bottom, left)
    panel.grid.major = element_line(color = "darkgray", size = 0.25),  # Darker major grid lines
    panel.grid.minor = element_line(color = "gray", size = 0.25),
      axis.title = element_text(size = 16),
    plot.title = element_text(size = 20)) +
  guides(color = guide_legend(title.position = "top", nrow = 6, byrow = TRUE)) +
#  scale_y_continuous(expand = expansion(mult = c(0.1, 0.1)),limits = c(-0.2, 0.2))   +
  scale_x_discrete(labels = function(x) sapply(x, add_line_breaks))+
  scale_color_manual(values=custom_disc_color) + guides(color = guide_legend(ncol = 2))
Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
Please use `linewidth` instead.Warning: The `size` argument of `element_line()` is deprecated as of ggplot2 3.4.0.
Please use the `linewidth` argument instead.
plot_eff2 <- ggplot(coef_df2, aes(color = Profession, y = estimate, x= term)) +
  geom_point(position = position_dodge(width = 0.8), size = 3)  +
  geom_errorbar(aes(ymin = estimate -  1.96 *std.error, ymax = estimate +  1.96 *std.error),
                width = 0.2, size = 1, position = position_dodge(width = 0.8)) +
  geom_vline(xintercept = 0, linetype = "solid", color = "black", size = 1.2)+
  coord_flip() +
  theme_minimal() +
  labs(
       x = "Coefficient Term",
       y = "Estimate",
       color = "Profession") +
theme(axis.text.x = element_text(size = 16),
        axis.text.y = element_text(size = 16),
          axis.title = element_text(size = 16),
        # Adjust margins (top, right, bottom, left)
    panel.grid.major = element_line(color = "darkgray", size = 0.25),  # Darker major grid lines
    panel.grid.minor = element_line(color = "gray", size = 0.25),
    plot.title = element_text(size = 20),
        legend.position = "bottom",   legend.text = element_text(size = 14),
      plot.margin = margin(t = 10, r = 40, b = 10, l = 10),
  legend.title = element_text(size = 16)) +
  guides(color = guide_legend(title.position = "top", nrow = 6, byrow = TRUE)) +
  scale_y_continuous(expand = expansion(mult = c(0.15, 0.15)),limits = c(-0.21, 0.21))   +
  scale_x_discrete(labels = function(x) sapply(x, add_line_breaks))+
  scale_color_manual(values=custom_disc_color)

plot_eff1

library(ggplot2)
library(ggpubr)

Attaching package: ‘ggpubr’

The following object is masked from ‘package:huxtable’:

    font
# Arrange with shared legend
combined <- ggarrange(
  plot_eff1, plot_eff2,
  ncol = 2, nrow = 1,
  common.legend = TRUE,   # <- share legend
  legend = "bottom"       # <- put legend below
)

# Save as PNG
ggsave("./Outputs/Figures/plots_combined.png", combined,
       width = 12, height = 12, units = "in", dpi = 600)

LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQogCgoKYGBge3IgZmlnLmhlaWdodD0xMiwgZmlnLndpZHRoPTE2fQoKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KHNmKQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KHNwYXRpYWxyZWcpCmxpYnJhcnkoc3BkZXApCgpybShsaXN0PWxzKCkpCm15cGF0aCA8LSAiLi9EYXRhQmFja3Vwcy8iCnByb2Zlc3Npb25fbmFtZXMgPC0gYygKICAic2FsZXMgcHJvZmVzc2lvbnMiLAogICJtZWNoYXRyb25pY3MsIGVuZXJneSwgYW5kIGVsZWN0cmljYWwgcHJvZmVzc2lvbnMiLAogICJwcm9mZXNzaW9ucyBpbiBidXNpbmVzcyBtYW5hZ2VtZW50IGFuZCBvcmdhbml6YXRpb24iLAogICJtZWRpY2FsIGhlYWx0aCBwcm9mZXNzaW9ucyIsCiAgIm1hY2hpbmUgYW5kIHZlaGljbGUgdGVjaG5vbG9neSBwcm9mZXNzaW9ucyIsCiAgImFsbCBwcm9mZXNzaW9ucyIKKQoKa3JlaXNlIDwtIHNmOjpzdF9yZWFkKCIuL0RhdGFQcmVwYXJhdGlvbi9TaGFwZXMvS3JlaXNlL3ZnMTAwMF8xMi0zMS51dG0zMnMuc2hhcGUuZWJlbmVuL3ZnMTAwMF9lYmVuZW5fMTIzMS9WRzEwMDBfS1JTLnNocCIpICMgdGhvdWdoIG5vdCBpbXBvcnRlZCBkaXJlY3RseSwgYWxsIG90aGVyIGF1eGlsaWFyeSBmaWxlcyBtdXN0IGJlIHByZXNlbnQgaW4gdGhlIHBhdGgKa3JlaXNlIDwtIHN0X3RyYW5zZm9ybShrcmVpc2UsICJXR1M4NCIpCmtyZWlzZV9tZXJnZWQgPC0ga3JlaXNlICU+JQogIGdyb3VwX2J5KFNOX0wpICU+JQogIHN1bW1hcml6ZShnZW9tZXRyeSA9IHN0X3VuaW9uKGdlb21ldHJ5KSkKYGBgCgpgYGB7ciBmaWcuaGVpZ2h0PTEyLCBmaWcud2lkdGg9MTZ9CmxpYnJhcnkoc3RyaW5ncikKbGlicmFyeShnZ3JlcGVsKQoKCm1vZGVsX2xpc3QgPC0gbGlzdCgpCgpncmFwaGljc19saXN0IDwtIGxpc3QoKQpzcGF0aWFsX2NsdXN0ZXJpbmdfbGlzdCA8LSBsaXN0KCkKbG9hZChmaWxlID0gIi4vRGF0YUJhY2t1cHMvd2VpZ2h0c19kYXRhLlJEYXRhIikKCmZvciAocCBpbiBwcm9mZXNzaW9uX25hbWVzKQp7CiNwIDwtIHByb2Zlc3Npb25fbmFtZXNbMV0gIAogIApsb2FkKHBhc3RlMChteXBhdGgscCwiTS5SZGF0YSIpKQpsb2FkKGZpbGUgPSAiLi9EYXRhQmFja3Vwcy93ZWlnaHRzX2RhdGEuUkRhdGEiKQoKcHJpbnQocCkKCnRhcmdldCA9ICJNIgpmb3JtdWxhX2Jhc2UgPC0gYXMuZm9ybXVsYShwYXN0ZTAodGFyZ2V0LCIgIH4gVSArIFYgIikpCmZvcm11bGEgPC0gYXMuZm9ybXVsYShwYXN0ZTAodGFyZ2V0LCIgICB+IFUgKyBWICsgdW5lbXAyNSArIGNvbnMgKyBoaWdoU0UgKyAgbWVkU0UgICIpKQpmb3JtdWxhX3B1Yl9udW0gPC0gYXMuZm9ybXVsYShwYXN0ZTAodGFyZ2V0LCIgICB+IFUgKyBWICsgdW5lbXAyNSArIGNvbnMgKyBoaWdoU0UgKyBtZWRTRSAgKyBBZ2dsb21lcmF0aW9uIikpCnRhcmdldCA9ICJNIgoKCgpwcm9mZXNzaW9uX25ldyRBZ2dsb21lcmF0aW9uIDwtIHByb2Zlc3Npb25fbmV3JEFnZ2xvbWVyYXRpb25QdWJsaWNQb3A0OQoKCiMgQmVnaW4gV2VpZ2h0IE1hdHJpeCBjb21wdXRhdGlvbgpjb2x1bW5zX29mX2ludGVyZXN0IDwtIGMoJ00nLCdVJywgJ1YnLCAndW5lbXAyNScsICdjb25zJywgJ2xvd1NFJywgJ21lZFNFJywgJ0FnZ2xvbWVyYXRpb24nKQojIFJlcGxhY2UgSW5mIGFuZCAtSW5mIHdpdGggTkEgaW4gdGhlIHNwZWNpZmllZCBjb2x1bW5zCnByb2Zlc3Npb25fbmV3W2NvbHVtbnNfb2ZfaW50ZXJlc3RdIDwtIGxhcHBseShwcm9mZXNzaW9uX25ld1tjb2x1bW5zX29mX2ludGVyZXN0XSwgZnVuY3Rpb24oeCkgcmVwbGFjZSh4LCBpcy5pbmZpbml0ZSh4KSwgTkEpKQojIFJlbW92ZSByb3dzIHdpdGggYW55IE5BIHZhbHVlcyBpbiB0aGUgc3BlY2lmaWVkIGNvbHVtbnMKcHJvZmVzc2lvbl9uZXcgPC0gcHJvZmVzc2lvbl9uZXdbY29tcGxldGUuY2FzZXMocHJvZmVzc2lvbl9uZXdbY29sdW1uc19vZl9pbnRlcmVzdF0pLCBdCgpiZXN0X1dlaWdodHNfcHVibGljX3BvcCA8LSBiZXN0X1dlaWdodHNfcHVibGljX3BvcF9tYXRbY29sbmFtZXMoYmVzdF9XZWlnaHRzX3B1YmxpY19wb3BfbWF0KSAlaW4lIHByb2Zlc3Npb25fbmV3JHJlZ2lvbixjb2xuYW1lcyhiZXN0X1dlaWdodHNfcHVibGljX3BvcF9tYXQpICVpbiUgcHJvZmVzc2lvbl9uZXckcmVnaW9uXQoKIyMjIyMjIyMjIyMjIyMjIwpsaWJyYXJ5KGRwbHlyKQoKZGlzdGFuY2VzX3JlbGV2YW50X3BvcCA8LSBtZXJnZShkaXN0YW5jZXNfcmVsZXZhbnQsZmluYWwsIGJ5Lng9ImNpdHkuLi4xIixieS55PSJjaXR5IikKZGlzdGFuY2VzX3JlbGV2YW50X3BvcCA8LSBtZXJnZShkaXN0YW5jZXNfcmVsZXZhbnRfcG9wLGZpbmFsLGJ5Lng9ImNpdHkuLi40IixieS55PSJjaXR5IikKCnByb2Zlc3Npb25fbmV3IDwtIHByb2Zlc3Npb25fbmV3WyFpcy5uYShwcm9mZXNzaW9uX25ldyRPcGVuUG9zaXRpb25zKSxdCgojIyBBcyBhbGwgUHJvZmVzc2lvbnMgaGF2ZSBkaWZmZXJlbnQgUmVnaW9ucywgd2UgbmVlZCB0byBSZWR1Y2UgdGhlIG1hdHJpeCB0byByZWxldmFudCByZWdpb25zLiBBcyB0aGUgaW5pdGlhbCBtYXRyaXgsIGFscmVhZHkgZG9lcyBub3QgY29udGFpbiBhbGwgcmVnaW9ucywgaXQgaXMgZWFzaWVyIHRvIHJlLWNhbGN1bGF0ZSBldnJ5dGhpbmcuCmRpc3RhbmNlc19yZWxldmFudF90ZXN0X3B1YmxpYyA8LSAgZGlzdGFuY2VzX3JlbGV2YW50X3BvcCAlPiUgZ3JvdXBfYnkoQUJEaXN0cmljdC4uLjYpICU+JSBtdXRhdGUoZGlzdHJpY3RfcG9wID0gc3VtKHVuaXF1ZShtYXhQb3B1bGF0aW9uLnkpKSkgJT4lIHVuZ3JvdXAgJT4lIGZpbHRlcihBQkRpc3RyaWN0Li4uMyAhPSBBQkRpc3RyaWN0Li4uNikgICU+JSAgZmlsdGVyKHB1YmxpYyA8PSA1MS4yODE2NykgJT4lIGdyb3VwX2J5KGNpdHkuLi4xLCBBQkRpc3RyaWN0Li4uMywgQUJEaXN0cmljdC4uLjYpICU+JSAgc3VtbWFyaXNlKGRpc3RyaWN0X3BvcCA9IG1heChkaXN0cmljdF9wb3ApLCBjb3VudD0gc3VtKHVuaXF1ZShtYXhQb3B1bGF0aW9uLnkpKSwgV2VpZ2h0PWNvdW50L2Rpc3RyaWN0X3BvcCwgLmdyb3Vwcz0ia2VlcCIpICU+JSBncm91cF9ieShBQkRpc3RyaWN0Li4uMywgQUJEaXN0cmljdC4uLjYpICU+JSBzdW1tYXJpc2UoV2VpZ2h0PW1lYW4oV2VpZ2h0KSwgLmdyb3Vwcz0ia2VlcCIpCgoKV2VpZ2h0c19wdWJsaWNfcG9wICA8LSBtYXRyaXgoMCwgbnJvdz1ucm93KHByb2Zlc3Npb25fbmV3KSwgbmNvbD1ucm93KHByb2Zlc3Npb25fbmV3KSkKICByb3cubmFtZXMoV2VpZ2h0c19wdWJsaWNfcG9wKTwtIHByb2Zlc3Npb25fbmV3JHJlZ2lvbgogIGNvbG5hbWVzKFdlaWdodHNfcHVibGljX3BvcCkgPC0gcHJvZmVzc2lvbl9uZXckcmVnaW9uCgogIGZvcihpIGluIDE6bnJvdyhkaXN0YW5jZXNfcmVsZXZhbnRfdGVzdF9wdWJsaWMpKQogIHsKICAgIFdlaWdodHNfcHVibGljX3BvcFtyb3cubmFtZXMoV2VpZ2h0c19wdWJsaWNfcG9wKT09ZGlzdGFuY2VzX3JlbGV2YW50X3Rlc3RfcHVibGljJEFCRGlzdHJpY3QuLi4zW2ldLCBjb2xuYW1lcyhXZWlnaHRzX3B1YmxpY19wb3ApPT1kaXN0YW5jZXNfcmVsZXZhbnRfdGVzdF9wdWJsaWMkQUJEaXN0cmljdC4uLjZbaV1dPC0gZGlzdGFuY2VzX3JlbGV2YW50X3Rlc3RfcHVibGljJFdlaWdodFtpXQogIH0KICAKICBXZWlnaHRzX3B1YmxpY19wb3AgPC0gV2VpZ2h0c19wdWJsaWNfcG9wL21heChXZWlnaHRzX3B1YmxpY19wb3ApCgogIG1vZGVsIDwtIGxtU0xYKGZvcm11bGFfcHViX251bSAsIHByb2Zlc3Npb25fbmV3LCBtYXQybGlzdHcoV2VpZ2h0c19wdWJsaWNfcG9wLCBzdHlsZT0iTSIpLCBuYS5hY3Rpb249bmEub21pdCwgemVyby5wb2xpY3k9VFJVRSwgRHVyYmluPX4gIFUgKyBWICAtMSkKCiAgbW9kZWxfbGlzdCR4IDwtIG1vZGVsCiAgbmFtZXMobW9kZWxfbGlzdCk8LWMobmFtZXMobW9kZWxfbGlzdClbMToobGVuZ3RoKG5hbWVzKG1vZGVsX2xpc3QpKSktMV0sIHApCiAgCiAgIwogIGVzdGltYXRlX3ZlY3RvcjwtIG1vZGVsJGNvZWZmaWNpZW50c1stYygyLDMsOToxMCldCiAgZXN0aW1hdGVfdmFsdWVzIDwtIGFzLm1hdHJpeChjYmluZCgiKEludGVyY2VwdCkiPTEsc3RfZHJvcF9nZW9tZXRyeShwcm9mZXNzaW9uX25ld1ssbmFtZXMoZXN0aW1hdGVfdmVjdG9yWy1jKDEpXSldKSkpCiAgCiAgCiAgcHJvZmVzc2lvbl9uZXckRWZmaWNpZW5jeSA8LSBleHAoZXN0aW1hdGVfdmFsdWVzICUqJSBlc3RpbWF0ZV92ZWN0b3IpIAoKbWFwX2VmZmljaWVuY3kgPC0gZ2dwbG90KCkgKyAKICBnZW9tX3NmKGRhdGE9ZGlzdHJpY3RzLCBmaWxsID0gIiNlNGU0ZTQiKSArCiAgZ2VvbV9zZihkYXRhPXN0X2FzX3NmKHByb2Zlc3Npb25fbmV3KSwgYWVzKGZpbGwgPSBFZmZpY2llbmN5KSkrCiAgZ2VvbV9zZihkYXRhPWtyZWlzZV9tZXJnZWQsZmlsbD1OQSwKICAgICAgICAgIGNvbG9yID0gIiNlYzcwNjMiLCAgIAogICAgICAgICAgbHdkID0gMS4yKSArCiAgdGhlbWUobGVnZW5kLnRleHQuYWxpZ24gPSAxKSAgKwogIGxhYnMoZmlsbCA9IHN0cl93cmFwKHBhc3RlMCgiRWZmaWNpZW5jeSBmb3IgIiwgcCksIHdpZHRoID0gNTApKSArIAogIGd1aWRlcygKICAgIGZpbGwgPSBndWlkZV9jb2xvcmJhcihkaXJlY3Rpb24gPSAiaG9yaXpvbnRhbCIsIHRpdGxlLmhqdXN0PTAuNSwgdGl0bGUucG9zaXRpb249InRvcCIsIGJhcndpZHRoID0gMjAsICAjIEFkanVzdCB0aGlzIHZhbHVlIHRvIGNoYW5nZSB0aGUgd2lkdGggb2YgdGhlIGNvbG9yYmFyCiAgICAgIGJhcmhlaWdodCA9IDEgICksIAojIEFkanVzdCByb3dzIGZvciB0aGUgZmlsbCBsZWdlbmQKICApICsKICB0aGVtZSgKICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLAogICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE4KSwKICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTgsIGZhY2U9ImJvbGQiKSwKICAgIGxlZ2VuZC5ib3ggPSAiaG9yaXpvbnRhbCIsCiAgICBsZWdlbmQuYm94Lmp1c3QgPSAiY2VudGVyIiwKICAgIGxlZ2VuZC5zcGFjaW5nLnggPSB1bml0KDAuNSwgImNtIikgCiAgKQoKCm1hcF9lZmZpY2llbmN5IDwtIG1hcF9lZmZpY2llbmN5ICsgIHNjYWxlX2ZpbGxfZ3JhZGllbnRuKGNvbG9ycyA9IGN1c3RvbV9jb2xvcnMoMTAwKSwgbmEudmFsdWU9IiNlNGU0ZTQiKQpwcmludChtYXBfZWZmaWNpZW5jeSkKCgogIGdyYXBoaWNzX2xpc3QkeCA8LSBtYXBfZWZmaWNpZW5jeQogIG5hbWVzKGdyYXBoaWNzX2xpc3QpPC1uYW1lcyhtb2RlbF9saXN0KQoKfQoKYGBgCgoKCmBgYHtyIGZpZy5oZWlnaHQ9MjQsIGZpZy53aWR0aD0xNn0KCmxpYnJhcnkoZ3JpZEV4dHJhKQpjb21iaW5lZF9wbG90IDwtIGRvLmNhbGwoZ3JpZC5hcnJhbmdlLCBjKGdyYXBoaWNzX2xpc3QsIG5jb2wgPSAyLCBucm93ID0gMykpCnByaW50KGNvbWJpbmVkX3Bsb3QpCgoKI2NvbWJpbmVkX3Bsb3QgPC0gZG8uY2FsbChncmlkLmFycmFuZ2UsIGMoc3BhdGlhbF9jbHVzdGVyaW5nX2xpc3QsIG5jb2wgPSAyLCBucm93ID0gMykpCiNwcmludChjb21iaW5lZF9wbG90KQoKCmBgYAoKYGBge3J9CmxpYnJhcnkoanRvb2xzKQpsaWJyYXJ5KGh1eHRhYmxlKQojIENvbWJpbmUgbW9kZWwgc3VtbWFyaWVzIGludG8gYSBzaW5nbGUgaHV4dGFibGUKaHQgPC0gZXhwb3J0X3N1bW1zKG1vZGVsX2xpc3QkYGFsbCBwcm9mZXNzaW9uc2AsCiAgICAgICAgICAgICAgICAgICBtb2RlbF9saXN0JGBtYWNoaW5lIGFuZCB2ZWhpY2xlIHRlY2hub2xvZ3kgcHJvZmVzc2lvbnNgLAogICAgICAgICAgICAgICAgICAgbW9kZWxfbGlzdCRgbWVjaGF0cm9uaWNzLCBlbmVyZ3ksIGFuZCBlbGVjdHJpY2FsIHByb2Zlc3Npb25zYCwKICAgICAgICAgICAgICAgICAgIG1vZGVsX2xpc3QkYG1lZGljYWwgaGVhbHRoIHByb2Zlc3Npb25zYCwKICAgICAgICAgICAgICAgICAgIG1vZGVsX2xpc3QkYHByb2Zlc3Npb25zIGluIGJ1c2luZXNzIG1hbmFnZW1lbnQgYW5kIG9yZ2FuaXphdGlvbmAsCiAgICAgICAgICAgICAgICAgICBtb2RlbF9saXN0JGBzYWxlcyBwcm9mZXNzaW9uc2AsCiAgICAgICAgICAgICAgICAgICBtb2RlbC5uYW1lcyA9IGMoIkFsbCBQcm9mZXNzaW9ucyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk1hY2hpbmUgJiBWZWhpY2xlIFRlY2hub2xvZ3kiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJNZWNoYXRyb25pY3MsIEVuZXJneSwgRWxlY3RyaWNhbCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk1lZGljYWwgSGVhbHRoIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQnVzaW5lc3MgTWFuYWdlbWVudCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlNhbGVzIiksIAogIG51bWJlcl9mb3JtYXQgPSAiJS4zZiIsIAogIHN0YXRpc3RpY3MgPSBjKCJsb2dMaWsiLCJBSUMiLCJCSUMiLCJOLiBvYnMuIiA9ICJub2JzIiksCiAgc3RhcnMgPSBjKGAqKipgID0gMC4wMDEsIGAqKmAgPSAwLjAxLCBgKmAgPSAwLjA1LCBgXmAgPSAwLjEpKQoKIyBBcHBseSBhbnkgYWRkaXRpb25hbCBmb3JtYXR0aW5nIHRvIHRoZSBodXh0YWJsZSBpZiBuZWVkZWQKaHQgPC0gaHQgJT4lCiAgCiAgc2V0X2hlYWRlcl9yb3dzKDEsIFRSVUUpICU+JQogIHNldF9oZWFkZXJfY29scygxLCBUUlVFKQoKIyBEaXNwbGF5IHRoZSBodXh0YWJsZQpwcmludF9zY3JlZW4oaHQpCgojIEV4cG9ydCB0byBIVE1MCnF1aWNrX2h0bWwoaHQsIGZpbGUgPSAiLi9PdXRwdXRzL1JlZ3Jlc3Npb25zL1Byb2Zlc3Npb25fZGlmZmVyZW5jZXMuaHRtbCIpCgoKCmBgYAoKCgpgYGB7UiBmaWcuaGVpZ2h0PTEwLCBmaWcud2lkdGg9N30KCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShkcGx5cikKbGlicmFyeSh0aWR5cikKbGlicmFyeShzdHJpbmdyKQpsaWJyYXJ5KGdncGxvdDIpCgoKCiMgRXh0cmFjdCBjb2VmZmljaWVudHMgYW5kIGNyZWF0ZSBhIGRhdGEgZnJhbWUKIyBFeHRyYWN0IGNvZWZmaWNpZW50cyBhbmQgY3JlYXRlIGEgZGF0YSBmcmFtZQojIEV4dHJhY3QgY29lZmZpY2llbnRzLCBzdGFuZGFyZCBlcnJvcnMgYW5kIGNyZWF0ZSBhIGRhdGEgZnJhbWUKY29lZl9kZiA8LSBkby5jYWxsKHJiaW5kLCBsYXBwbHkobmFtZXMobW9kZWxfbGlzdCksIGZ1bmN0aW9uKHByb2Zlc3Npb24pIHsKICBtb2RlbCA8LSBtb2RlbF9saXN0W1twcm9mZXNzaW9uXV0KICB0aWR5X21vZGVsIDwtIGJyb29tOjp0aWR5KG1vZGVsKQogIHRpZHlfbW9kZWwkUHJvZmVzc2lvbiA8LSBwcm9mZXNzaW9uCiAgdGlkeV9tb2RlbAp9KSkKCgojIEZ1bmN0aW9uIHRvIGFkZCBsaW5lIGJyZWFrcyB0byBsYWJlbHMKYWRkX2xpbmVfYnJlYWtzIDwtIGZ1bmN0aW9uKGxhYmVsLCB3aWR0aCA9IDMwKSB7CiAgc3RyX3dyYXAobGFiZWwsIHdpZHRoID0gd2lkdGgpCn0KCgoKICNFeHRyYWN0IGNvZWZmaWNpZW50cywgc3RhbmRhcmQgZXJyb3JzIGFuZCBjcmVhdGUgYSBkYXRhIGZyYW1lCmNvZWZfZGYgPC0gZG8uY2FsbChyYmluZCwgbGFwcGx5KG5hbWVzKG1vZGVsX2xpc3QpLCBmdW5jdGlvbihwcm9mZXNzaW9uKSB7CiAgbW9kZWwgPC0gbW9kZWxfbGlzdFtbcHJvZmVzc2lvbl1dCiAgdGlkeV9tb2RlbCA8LSBicm9vbTo6dGlkeShtb2RlbCkKICB0aWR5X21vZGVsJFByb2Zlc3Npb24gPC0gcHJvZmVzc2lvbgogIHRpZHlfbW9kZWwKfSkpCgojIENyZWF0ZSBhbiBvZmZzZXQgdmFyaWFibGUgZm9yIHRoZSB5LWF4aXMKY29lZl9kZiA8LSBjb2VmX2RmICU+JQogIGdyb3VwX2J5KHRlcm0pICU+JQogIG11dGF0ZShvZmZzZXQgPSBhcy5udW1lcmljKGZhY3RvcihQcm9mZXNzaW9uKSkgKiAwLjEpICU+JSAgIyBBZGp1c3QgdGhlIG9mZnNldCBtdWx0aXBsaWVyIGFzIG5lZWRlZAogIHVuZ3JvdXAoKQoKIyBBZGQgdGhlIEVuZ2xpc2ggcHJvZmVzc2lvbiBjb2x1bW4KCgoKY29lZl9kZiR0ZXJtW2NvZWZfZGYkdGVybT09IihJbnRlcmNlcHQpIl0gPC0gIkVmZmljaWVuY3kiCmNvZWZfZGYkdGVybVtjb2VmX2RmJHRlcm09PSJBZ2dsb21lcmF0aW9uRGlzdFBvcCJdIDwtICJBZ2dsb21lcmF0aW9uIgoKY29lZl9kZiR0ZXJtW2NvZWZfZGYkdGVybT09ImxhZy5VIl0gPC0gIlUubGFnIgpjb2VmX2RmJHRlcm1bY29lZl9kZiR0ZXJtPT0ibGFnLlYiXSA8LSAiVi5sYWciCgoKY29lZl9kZjEgPC0gY29lZl9kZltjb2VmX2RmJHRlcm0gJWluJSBjKCJVIiwiViIsIlUubGFnIiwiVi5sYWciLCJFZmZpY2llbmN5IiwgImxhbWJkYSIpLF0KCmNvZWZfZGYyIDwtIGNvZWZfZGZbIShjb2VmX2RmJHRlcm0gJWluJSBjKCJVIiwiViIsIlUubGFnIiwiVi5sYWciLCJFZmZpY2llbmN5IiwibGFtYmRhIikpLF0KCmxpYnJhcnkodmlyaWRpcykKbGlicmFyeShzY2FsZXMpCmRhcmtfdmlyaWRpc19jb2xvcnMgPC0gdmlyaWRpc19wYWwob3B0aW9uID0gIkciKSgxMClbMzo4XQoKIyBQbG90IHRoZSBjb2VmZmljaWVudHMgd2l0aCBlcnJvciBiYXJzIGFuZCB2ZXJ0aWNhbCBvZmZzZXQKCmNvZWZfZGYxJHRlcm0gPC0gZmFjdG9yKGNvZWZfZGYxJHRlcm0sIGxldmVscyA9IGMoImxhbWJkYSIsICJVLmxhZyIsIlYubGFnIiwgIlUiLCAiViIsICAiRWZmaWNpZW5jeSIgKSkKCnBsb3RfZWZmMSA8LSBnZ3Bsb3QoY29lZl9kZjEsIGFlcyh4ID0gdGVybSwgeSA9IGVzdGltYXRlLCBjb2xvciA9IFByb2Zlc3Npb24pKSsKICBnZW9tX3BvaW50KHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjgpLCBzaXplID0gMykgKwogIGdlb21fZXJyb3JiYXIoYWVzKHltaW4gPSBlc3RpbWF0ZSAtIDEuOTYgKiBzdGQuZXJyb3IsIHltYXggPSBlc3RpbWF0ZSArICAxLjk2ICpzdGQuZXJyb3IpLAogICAgICAgICAgICAgICAgd2lkdGggPSAwLjIsIHNpemUgPSAxLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC44KSkrCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMCwgbGluZXR5cGUgPSAic29saWQiLCBjb2xvciA9ICJibGFjayIsIHNpemUgPSA2KSArCiAgY29vcmRfZmxpcCgpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIGxhYnMoCiAgICAgICB4ID0gIkNvZWZmaWNpZW50IFRlcm0iLAogICAgICAgeSA9ICJFc3RpbWF0ZSIsCiAgICAgICBjb2xvciA9ICJQcm9mZXNzaW9uIikgKwp0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTYpLAogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNiksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0KSwKICAgICAgICBwbG90Lm1hcmdpbiA9IG1hcmdpbih0ID0gMTAsIHIgPSA0MCwgYiA9IDEwLCBsID0gMTApLAogIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTYpLAogIGxlZ2VuZC50aXRsZS5wb3NpdGlvbiA9ICJ0b3AiLAogIGxlZ2VuZC5ib3ggPSAiaG9yaXpvbnRhbCIsCiAgICAjIEFkanVzdCBtYXJnaW5zICh0b3AsIHJpZ2h0LCBib3R0b20sIGxlZnQpCiAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9saW5lKGNvbG9yID0gImRhcmtncmF5Iiwgc2l6ZSA9IDAuMjUpLCAgIyBEYXJrZXIgbWFqb3IgZ3JpZCBsaW5lcwogICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfbGluZShjb2xvciA9ICJncmF5Iiwgc2l6ZSA9IDAuMjUpLAogICAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNiksCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAyMCkpICsKICBndWlkZXMoY29sb3IgPSBndWlkZV9sZWdlbmQodGl0bGUucG9zaXRpb24gPSAidG9wIiwgbnJvdyA9IDYsIGJ5cm93ID0gVFJVRSkpICsKIyAgc2NhbGVfeV9jb250aW51b3VzKGV4cGFuZCA9IGV4cGFuc2lvbihtdWx0ID0gYygwLjEsIDAuMSkpLGxpbWl0cyA9IGMoLTAuMiwgMC4yKSkgICArCiAgc2NhbGVfeF9kaXNjcmV0ZShsYWJlbHMgPSBmdW5jdGlvbih4KSBzYXBwbHkoeCwgYWRkX2xpbmVfYnJlYWtzKSkrCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jdXN0b21fZGlzY19jb2xvcikgKyBndWlkZXMoY29sb3IgPSBndWlkZV9sZWdlbmQobmNvbCA9IDIpKQoKCgpwbG90X2VmZjIgPC0gZ2dwbG90KGNvZWZfZGYyLCBhZXMoY29sb3IgPSBQcm9mZXNzaW9uLCB5ID0gZXN0aW1hdGUsIHg9IHRlcm0pKSArCiAgZ2VvbV9wb2ludChwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC44KSwgc2l6ZSA9IDMpICArCiAgZ2VvbV9lcnJvcmJhcihhZXMoeW1pbiA9IGVzdGltYXRlIC0gIDEuOTYgKnN0ZC5lcnJvciwgeW1heCA9IGVzdGltYXRlICsgIDEuOTYgKnN0ZC5lcnJvciksCiAgICAgICAgICAgICAgICB3aWR0aCA9IDAuMiwgc2l6ZSA9IDEsIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjgpKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMCwgbGluZXR5cGUgPSAic29saWQiLCBjb2xvciA9ICJibGFjayIsIHNpemUgPSAxLjIpKwogIGNvb3JkX2ZsaXAoKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICBsYWJzKAogICAgICAgeCA9ICJDb2VmZmljaWVudCBUZXJtIiwKICAgICAgIHkgPSAiRXN0aW1hdGUiLAogICAgICAgY29sb3IgPSAiUHJvZmVzc2lvbiIpICsKdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE2KSwKICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTYpLAogICAgICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTYpLAogICAgICAgICMgQWRqdXN0IG1hcmdpbnMgKHRvcCwgcmlnaHQsIGJvdHRvbSwgbGVmdCkKICAgIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2xpbmUoY29sb3IgPSAiZGFya2dyYXkiLCBzaXplID0gMC4yNSksICAjIERhcmtlciBtYWpvciBncmlkIGxpbmVzCiAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9saW5lKGNvbG9yID0gImdyYXkiLCBzaXplID0gMC4yNSksCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAyMCksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0KSwKICAgICAgcGxvdC5tYXJnaW4gPSBtYXJnaW4odCA9IDEwLCByID0gNDAsIGIgPSAxMCwgbCA9IDEwKSwKICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE2KSkgKwogIGd1aWRlcyhjb2xvciA9IGd1aWRlX2xlZ2VuZCh0aXRsZS5wb3NpdGlvbiA9ICJ0b3AiLCBucm93ID0gNiwgYnlyb3cgPSBUUlVFKSkgKwogIHNjYWxlX3lfY29udGludW91cyhleHBhbmQgPSBleHBhbnNpb24obXVsdCA9IGMoMC4xNSwgMC4xNSkpLGxpbWl0cyA9IGMoLTAuMjEsIDAuMjEpKSAgICsKICBzY2FsZV94X2Rpc2NyZXRlKGxhYmVscyA9IGZ1bmN0aW9uKHgpIHNhcHBseSh4LCBhZGRfbGluZV9icmVha3MpKSsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWN1c3RvbV9kaXNjX2NvbG9yKQoKcGxvdF9lZmYxCmBgYAoKCgoKYGBge3J9CmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShnZ3B1YnIpCgoKIyBBcnJhbmdlIHdpdGggc2hhcmVkIGxlZ2VuZApjb21iaW5lZCA8LSBnZ2FycmFuZ2UoCiAgcGxvdF9lZmYxLCBwbG90X2VmZjIsCiAgbmNvbCA9IDIsIG5yb3cgPSAxLAogIGNvbW1vbi5sZWdlbmQgPSBUUlVFLCAgICMgPC0gc2hhcmUgbGVnZW5kCiAgbGVnZW5kID0gImJvdHRvbSIgICAgICAgIyA8LSBwdXQgbGVnZW5kIGJlbG93CikKCiMgU2F2ZSBhcyBQTkcKZ2dzYXZlKCIuL091dHB1dHMvRmlndXJlcy9wbG90c19jb21iaW5lZC5wbmciLCBjb21iaW5lZCwKICAgICAgIHdpZHRoID0gMTIsIGhlaWdodCA9IDEyLCB1bml0cyA9ICJpbiIsIGRwaSA9IDYwMCkKYGBgCgo=